package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.media.dto.MediaDTO;
import com.xuecheng.api.media.qo.QueryMediaModel;
import com.xuecheng.api.media.vo.MediaVO;
import com.xuecheng.content.common.domain.code.CommonErrorCode;
import com.xuecheng.content.common.domain.page.PageRequestParams;
import com.xuecheng.content.common.domain.page.PageVO;
import com.xuecheng.content.common.domain.response.RestResponse;
import com.xuecheng.content.common.enums.common.AuditEnum;
import com.xuecheng.content.common.enums.common.CommonEnum;
import com.xuecheng.content.common.enums.media.MediaEnum;
import com.xuecheng.content.common.exception.ExceptionCast;
import com.xuecheng.content.common.util.StringUtil;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.controller.MediaController;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 媒资信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {


    /*
     * 业务分析：
     *   1.判断关键
     *       companyid  filename  fileid(videoId)
     *   2.给信息数据赋值默认值
     *       auditStatus：未审核
     *
     *   3.保存信息
     *   4.将数据库最新数据返回
     *
     * */
    @Transactional
    public MediaDTO createMedia(MediaDTO dto) {

        //1.判断关键
        //     companyid  filename  fileid(videoId)
        if (ObjectUtils.isEmpty(dto.getCompanyId()) ||
                StringUtil.isBlank(dto.getFilename()) ||
                StringUtil.isBlank(dto.getFileId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }


        // 2.给信息数据赋值默认值
        //     auditStatus：未审核
        dto.setAuditStatus(AuditEnum.AUDIT_UNPAST_STATUS.getCode());


        // 3.保存信息
        Media media = MediaConvert.INSTANCE.dto2entity(dto);
        boolean result = this.save(media);

        if (!result) {
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }

        // 4.将数据库最新数据返回
        Media po = this.getById(media.getId());

        MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(po);

        return mediaDTO;
    }


    /*
    教学机构
    删除媒资信息接口业务实现
    1.判断关键数据
		mediaId、companyId
	2.判断业务数据
		媒资信息
			判断是否存在
			判断审核状态：只有审核通过不能删除
			判断媒资信息是否有绑定课程计划数据
				绑定媒资和课程计划数据：content（发送feign）
											   teachplan_media
	3.删除媒资信息
		媒资服务中的数据：Media
		阿里云对应的视频
     */
    @Override
    @Transactional
    public Boolean removeMediaId(long id, Long companyId) {
        //1.判断关键数据
        //	mediaId、companyId
        if (ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.判断业务数据
        //	媒资信息
        Media media = getById(id);

        //		判断是否存在
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        //		判断审核状态：只有审核通过不能删除
        if (!ObjectUtils.nullSafeEquals(companyId, media.getCompanyId())) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        if (AuditEnum.AUDIT_UNPAST_STATUS.equals(media.getAuditStatus()) ||
                AuditEnum.AUDIT_DISPAST_STATUS.equals(media.getAuditStatus())) {
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }
        // TODO: 2021/12/15
        //		判断媒资信息是否有绑定课程计划数据
        //			绑定媒资和课程计划数据：content（发送feign）
        //										   teachplan_media
        //3.删除媒资信息
        LambdaUpdateWrapper<Media> mediaLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        mediaLambdaUpdateWrapper.set(Media::getStatus, MediaEnum.CHARGE_YES.getCode());
        mediaLambdaUpdateWrapper.eq(Media::getId, media.getId());

        boolean update = this.update(mediaLambdaUpdateWrapper);

        if (!update) {
            ExceptionCast.cast(MediaErrorCode.E_140002);
        }
        //	媒资服务中的数据：Media
        //	阿里云对应的视频

        return update;
    }

    /*
    1.判断关键数据
    auditMind  auditStatus  courseid
2.判断业务数据
    课程基础信息
        判断是否存在
        判断是否删除
        判断审核状态
            必须为：已提交
    审核状态
        运营平台只能给课程审核状态赋值：审核通过、审核未通过
3.修改课程审核信息
    auditMind  auditStatus  auditNum（每次+1）
     */
    @Override
    @Transactional
    public boolean auditMedia(MediaVO vo) {
        //1.判断关键数据
        //    auditMind  auditStatus  courseid
        if (ObjectUtils.isEmpty(vo.getAuditMind()) ||
                ObjectUtils.isEmpty(vo.getAuditStatus()) ||
                ObjectUtils.isEmpty(vo.getId())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //获取媒资信息
        Media media = this.getById(vo.getId());
        //核实媒资状态
        if (media.getStatus().equals(CommonEnum.DELETE_FLAG.getCode())) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        if (media.getAuditStatus().equals(AuditEnum.AUDIT_PASTED_STATUS.getCode())) {
            ExceptionCast.cast(MediaErrorCode.E_140017);
        }

        //获取审核状态
        String auditStatus = vo.getAuditStatus();
        if (StringUtils.isBlank(auditStatus)) {
            ExceptionCast.cast(MediaErrorCode.E_140019);
        }
        if (!auditStatus.equals(AuditEnum.AUDIT_PASTED_STATUS.getCode())&&
                !auditStatus.equals(AuditEnum.AUDIT_DISPAST_STATUS.getCode())) {
            ExceptionCast.cast(MediaErrorCode.E_140017);
        }
        //2.判断业务数据
        //    课程基础信息
        //        判断是否存在
        //        判断是否删除
        //        判断审核状态
        //            必须为：已提交
        LambdaUpdateWrapper<Media> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Media::getId, vo.getId());
        wrapper.set(Media::getAuditStatus, vo.getAuditStatus());
        wrapper.set(Media::getAuditMind,vo.getAuditMind());

        //修改状态

        boolean update = this.update(wrapper);
        if (!update) {
            ExceptionCast.cast(MediaErrorCode.E_140020);
        }
        return update;
    }


    /*
        分页条件查询课程基本信息数据

        步骤分析：
         1.是否需要开启事务
         2.判断关键数据
              分页数据
              查询条件
         3.构建mp分页对象
         4.构建查询条件对象LambdaQueryWrapper
         5.查询数据
         6.获得数据并封装返回结果
              封装PageVo数据
         */
    @Override
    public PageVO queryMediaList(PageRequestParams params, QueryMediaModel model, Long companyId) {

        //1.判断分页的数据
        if (params.getPageNo() < 1) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }
        if (params.getPageSize() < 1) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }
        //2.添加条件查询
        LambdaQueryWrapper<Media> wrapper = new LambdaQueryWrapper<>();
        //判断条件查询（条件查询是否有数据，有数据添加条件）
        if (StringUtil.isNotBlank(model.getFilename())) {
            //根据课程名称模糊查询
            wrapper.like(Media::getFilename, model.getFilename());
        }
        //判断文件类型的状态
        if (StringUtil.isNotBlank(model.getType())) {
            //设置课程的条件
            wrapper.eq(Media::getType, model.getType());
        }
        //判断文件类型的状态
        if (StringUtil.isNotBlank(model.getAuditStatus())) {
            //设置课程的条件
            wrapper.eq(Media::getAuditStatus, model.getAuditStatus());
        }

        //判断机构的id 是否相等，相等的话，就不走这个wrapper.eq(CourseBase::getCompanyId,companyId);
        //不相等的话走查询所有机构的id
        if (!(ObjectUtils.nullSafeEquals(companyId, MediaController.OPERATION_FLAG))) {
            wrapper.eq(Media::getCompanyId, companyId);
        }


        //3.创建分页数据
        Page<Media> page = new Page<>(params.getPageNo(), params.getPageSize());
        //4.根据分页和条件查询list数据
        Page<Media> pageResult = this.page(page, wrapper);
        //获取list集合
        List<Media> mediaList = pageResult.getRecords();
        //获取总条数
        long total = pageResult.getTotal();

        // TODO: 2021/12/9
        //List<CourseBaseDTO> dtos;
        List<MediaDTO> dtos = Collections.emptyList();
        //判断是否为空
        if (!(CollectionUtils.isEmpty(mediaList))) {
            dtos = MediaConvert.INSTANCE.entitys2dtos(mediaList);
        }
        // 6.封装PageVO数据
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());

        return pageVO;
    }

    /*
    获得媒资信息预览资源地址
    1.判断关键数据
		mediaId、companyId
	2.判断业务数据
		媒资信息
			判断是否存在（mediaId、companyId）
			判断媒资类型，如果是视频的话，要获得阿里云视频点播的播放地址
	3.获得媒资资源的路径地址Url
			获得最新的播放地址，从阿里云上获得
			PS：优化--要从缓存中获得url（ps：缓存中必须存在url--1.创建media获得，2.服务端启动时来获得--定时任务）
			缓存中的url---设置缓存中的ttl
	4.返回结果内容
     */


    @Override
    public String previewMedia(Long mediaId, Long companyId) {
        // 1.判断关键数据
        //		mediaId、companyId
        if (ObjectUtils.isEmpty(mediaId) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //	2.判断业务数据
        //		媒资信息
        //			判断是否存在（mediaId、companyId）
        //			判断媒资类型，如果是视频的话，要获得阿里云视频点播的播放地址
        // 根据媒资id获得媒资信息
        Media media = getById(mediaId);
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(CommonErrorCode.E_100104);
        }
        //判断公司id，如果不是运营平台标示则判断公司id
        if (!(companyId.equals(MediaController.OPERATION_FLAG))) {
            if (!(media.getCompanyId().equals(companyId))) {
                ExceptionCast.cast(MediaErrorCode.E_140016);
            }
        }
        //定义返回的url字符串  方法
        String playUrl = getPlayUrl(media.getFileId());

        //	3.获得媒资资源的路径地址Url
        //			获得最新的播放地址，从阿里云上获得
        //		todo	PS：优化--要从缓存中获得url（ps：缓存中必须存在url--1.创建media获得，2.服务端启动时来获得--定时任务）

        //			缓存中的url---设置缓存中的ttl
        //	4.返回结果内容
        return playUrl;
    }

    /*
    业务分析：
  PS：由于是学成内部微服务间的调用，此功能只需要提供基础数据即可，不需要加上业务逻辑判断
  如果为了数据的完整性，可以对传入和传出的参数进行判断
  1.判断mediaid是否为空
  2.查询数据
  3.判断数据是否存在
  4.如果存在，使用RestResponse来封装返回
     */
    @Override
    public RestResponse<MediaDTO> getById4Service(Long mediaId) {
        // 1.判断关键数据
        if (ObjectUtils.isEmpty(mediaId)) {
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }

        // 2.判断业务数据
        Media media = this.getById(mediaId);

        if (ObjectUtils.isEmpty(media)) {
            return RestResponse.validfail(MediaErrorCode.E_140005);
        } else {

            MediaDTO mediaDTO = MediaConvert.INSTANCE.entity2dto(media);
            return RestResponse.success(mediaDTO);
        }

    }


    //阿里云的地区 ak  sk都在nacos里
    @Value("${aliyun.region}")
    private String region;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;

    private String getPlayUrl(String videoId) {

        String playUrl = "";

        try {

            DefaultAcsClient client = AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);

            GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client, videoId);

            List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();

            if (!(ObjectUtils.isEmpty(playInfoList))) {
                GetPlayInfoResponse.PlayInfo playInfo = playInfoList.get(0);
                playUrl = playInfo.getPlayURL();
            }

        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140014);
        }
        return playUrl;
    }

}







